#include "LinkedList.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

LinkedList *linked_list_create() {
    LinkedList *linked_list = malloc(sizeof(LinkedList));
    linked_list->head.prev  = &linked_list->head;
    linked_list->head.next  = &linked_list->head;
    linked_list->size       = 0;
    linked_list->match      = strcmp;
    linked_list->freeValue  = free;
    return linked_list;
}

void linked_list_free(LinkedList *linked_list) {
    Node *p = linked_list->head.next;
    while (p != &linked_list->head) {
        Node *temp = p;
        p          = p->next;
        linked_list->freeValue(temp->value);
        free(temp);
    }
    free(linked_list);
}

void linked_list_reset(LinkedList *linked_list) {
    Node *p = linked_list->head.next;
    while (p != &linked_list->head) {
        Node *temp = p;
        p          = p->next;
        linked_list->freeValue(temp);
    }
    linked_list->head.prev = &linked_list->head;
    linked_list->head.next = &linked_list->head;
    linked_list->size      = 0;
}

void *linked_list_get(const LinkedList *linked_list, void *value) {
    Node *p = linked_list->head.next;
    while (p != &linked_list->head) {
        if (linked_list->match(p->value, value)) {
            return p->value;
        }
        p = p->next;
    }
    return NULL;
}

void *linked_list_get_l(LinkedList *linked_list) { return linked_list->head.next->value; }

void *linked_list_get_r(LinkedList *linked_list) { return linked_list->head.prev->value; }

void linked_list_add_l(LinkedList *linked_list, void *value) {
    Node *node                   = malloc(sizeof(Node));
    node->value                  = value;
    node->prev                   = &linked_list->head;
    node->next                   = linked_list->head.next;
    linked_list->head.next->prev = node;
    linked_list->head.next       = node;
    linked_list->size++;
}

void linked_list_add_r(LinkedList *linked_list, void *value) {
    Node *node                   = malloc(sizeof(Node));
    node->value                  = value;
    node->prev                   = linked_list->head.prev;
    node->next                   = &linked_list->head;
    linked_list->head.prev->next = node;
    linked_list->head.prev       = node;
    linked_list->size++;
}

/**
 * 从链表中删除节点（不释放内存）
 */
void linked_list_remove_node(LinkedList *linked_list, Node *node) {
    node->prev->next = node->next;
    node->next->prev = node->prev;
    linked_list->size--;
}

void linked_list_full_remove_node(LinkedList *linked_list, Node* node) {
    node->prev->next = node->next;
    node->next->prev = node->prev;
    linked_list->size--;
    linked_list->freeValue(node->value);
    free(node);
}

void *linked_list_pop(LinkedList *linked_list, void *value) {
    Node *p = linked_list->head.next;
    while (p != &linked_list->head) {
        if (linked_list->match(p->value, value)) {
            linked_list_remove_node(linked_list, p);
            void *temp = p->value;
            free(p);
            return temp;
        }
        p = p->next;
    }
    return NULL;
}

void *linked_list_pop_l(LinkedList *linked_list) {
    if (linked_list_is_empty(linked_list)) {
        return NULL;
    }
    Node *p       = linked_list->head.next;
    p->prev->next = p->next;
    p->next->prev = p->prev;

    void *temp = p->value;
    free(p);
    linked_list->size--;

    return temp;
}

void *linked_list_pop_r(LinkedList *linked_list) {
    if (linked_list_is_empty(linked_list)) {
        return NULL;
    }
    Node *p       = linked_list->head.prev;
    p->prev->next = p->next;
    p->next->prev = p->prev;

    void *temp = p->value;
    free(p);
    linked_list->size--;

    return temp;
}

/**
 * 把链表中的节点移动到链表尾部
 */
void linked_list_push_back(LinkedList *linked_list, Node *node) {
    // 从链表中删除节点
    linked_list_remove_node(linked_list, node);
    // 添加到链表尾部
    linked_list_add_r(linked_list, node);
}

LinkedListIterator *linked_list_iterator_create(LinkedList *linked_list) {
    LinkedListIterator *iterator = malloc(sizeof(LinkedListIterator));
    iterator->linked_list        = linked_list;
    iterator->node               = linked_list->head.next;

    return iterator;
}

Node *linked_list_iterator_next(LinkedListIterator *iterator) {
    if (iterator->node == &iterator->linked_list->head)
        return NULL;
    Node *temp     = iterator->node;
    iterator->node = iterator->node->next;
    return temp;
}

void linked_list_iteraotr_reset(LinkedListIterator *iterator) { iterator->node = iterator->linked_list->head.next; }

void linked_list_iterator_free(LinkedListIterator *iterator) { free(iterator); }

int linked_list_len(LinkedList *linked_list) { return linked_list->size; }

bool linked_list_is_empty(const LinkedList *linked_list) { return linked_list->size == 0;
}